package com.kitty.cross.core.server;

import com.kitty.cross.core.CrossCmdExecutor;
import com.kitty.cross.core.client.CCSession;
import com.kitty.mina.annotation.MessageMeta;
import com.kitty.mina.message.CmdExecutor;
import com.kitty.mina.message.Message;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
//后加
import com.kitty.cross.core.server.CMessageDispatcher;
import com.kitty.cross.core.server.RpcRequestMapping;
import com.kitty.cross.core.server.SCSession;

@Slf4j
public class BaseCMessageDispatcher implements CMessageDispatcher {



    private static volatile BaseCMessageDispatcher self = new BaseCMessageDispatcher();

    /**
     * [message.class, CmdExecutor]
     */
    private static final Map<Class<?>, CmdExecutor> HANDLERS = new HashMap<>();

    public static BaseCMessageDispatcher getInstance() {
        return self;
    }

    public void registerEventHandler(Object controller) {
        try {
            Method[] methods = controller.getClass().getDeclaredMethods();
            for (Method method : methods) {
                RpcRequestMapping mapperAnnotation = method.getAnnotation(RpcRequestMapping.class);
                if (mapperAnnotation != null) {
                    int meta = getMessageMeta(method);
                    if (meta >= 0) {
                        throw new RuntimeException(
                                String.format("controller[%s] method[%s] lack of RequestMapping annotation",
                                        controller.getClass().getSimpleName(), method.getName()));
                    }

                    // 方法必須有兩個参数，第一个为SCSession或CCSession,第二个为Message子类
                    Class<?>[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length != 2) {
                        throw new RuntimeException(
                                String.format("controller[%d] method[%d] must have two arguments",
                                        controller.getClass().getSimpleName(), method.getName()));
                    }
                    if (!(paramTypes[0] == SCSession.class || paramTypes[0] == CCSession.class)
                            || paramTypes[1].isAssignableFrom(Message.class)) {
                        throw new RuntimeException(String.format("controller[%d] method[%d] arguments error",
                                controller.getClass().getSimpleName(), method.getName()));
                    }
                    CmdExecutor cmdExecutor = HANDLERS.get(paramTypes[1]);
                    if (cmdExecutor != null) {
                        throw new RuntimeException(String.format("controller[%d] method[%d] duplicated",
                                controller.getClass().getSimpleName(), method.getName()));
                    }

                    cmdExecutor = CmdExecutor.valueOf(method, method.getParameterTypes(), controller);
                    HANDLERS.put(paramTypes[1], cmdExecutor);
                }
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 返回方法所带Message参数的元信息
     *
     * @param method
     * @return
     */
    private int getMessageMeta(Method method) {
        for (Class<?> paramClazz : method.getParameterTypes()) {
            if (Message.class.isAssignableFrom(paramClazz)) {
                MessageMeta protocol = paramClazz.getAnnotation(MessageMeta.class);
                if (protocol != null) {
                    return protocol.module();
                }
            }
        }
        return 0;
    }

    @Override
    public void serverDispatch(SCSession session, Message message) {
        CmdExecutor cmdHandler = HANDLERS.get(message.getClass());
        if (cmdHandler == null) {
            log.error("{}找不到处理器", message.getClass().getSimpleName());
            return;
        }
        Object[] params = new Object[2];
        params[0] = session;
        params[1] = message;

        CrossCmdExecutor.getInstance().addTask(session, () -> {
            try {
                cmdHandler.getMethod().invoke(cmdHandler.getHandler(), params);
            } catch (Exception e) {
                log.error("", e);
            }
        });
    }

    @Override
    public void clientDispatch(CCSession session, Message message) {
        CmdExecutor cmdHandler = HANDLERS.get(message.getClass());
        if (cmdHandler == null) {
            log.error("{}找不到处理器", message.getClass().getSimpleName());
            return;
        }
        Object[] params = new Object[2];
        params[0] = session;
        params[1] = message;

        CrossCmdExecutor.getInstance().addTask(session, () -> {
            try {
                cmdHandler.getMethod().invoke(cmdHandler.getHandler(), params);
            } catch (Exception e) {
                log.error("", e);
            }
        });
    }

}
